﻿using AutoMapper;
using Microsoft.EntityFrameworkCore;
using QMERP.Domain.Dtos;
using QMERP.Domain.Entities;
using QMERP.Domain.Enums;
using QMERP.Infrastructure.CustomException;
using QMERP.Infrastructure.EFCore;
using QMERP.Infrastructure.EFCore.Extensions;
using QMERP.Infrastructure.Extensions;
using QMERP.Infrastructure.Security;
using System.Data;

namespace QMERP.Application.Services
{
    public class ContractService : IContractService
    {
        private readonly IMapper _mapper;
        private readonly QMERPDbContext _db;
        private readonly ISerialNumberService _serialNumberSvc;
        private readonly ICurrentUser _currentUser;
        public ContractService(IMapper mapper, QMERPDbContext db, ISerialNumberService serialNumberSvc, ICurrentUser currentUser)
        {
            _mapper = mapper;
            _db = db;
            _serialNumberSvc = serialNumberSvc;
            _currentUser = currentUser;
        }
        /// <summary>
        /// 获取合约列表基础数据
        /// </summary>
        /// <returns></returns>
        public async Task<List<ContractResponse>> GetBasicContracts()
        {
            var list = await _db.Contract.ToListAsync();
            return _mapper.Map<List<ContractResponse>>(list);
        }
        /// <summary>
        /// 获取此客户的所有的可用合约
        /// </summary>
        /// <param name="customerId"></param>
        /// <returns></returns>
        public async Task<List<ContractResponse>> GetContractByCustomerId(long customerId)
        {
            var contracts = await _db.Contract.Include(x => x.Contract_Customers).Include(x => x.Contract_Lenses).ThenInclude(x => x.Lens).Where(x => x.Contract_Customers.Select(s => s.CustomerId).Contains(customerId)).ToListAsync();
            return _mapper.Map<List<ContractResponse>>(contracts);
        }
        /// <summary>
        /// 获取此仓库库存的合约镜种
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<List<Contract_LensResponse>> GetStockContractLenses(GetStockContractLensesRequest request)
        {
            var contract_lenses = await (from a in _db.Contract_Lens.Include(x => x.Lens)
                                         from b in _db.Lens_Supplier.Where(x=>x.LensId == a.LensId).DefaultIfEmpty()
                                         join c in _db.Stock on a.LensId equals c.LensId
                                         where a.ContractId == request.ContractId && b.SupplierId == request.SupplierId && c.WarehouseId == request.WarehouseId
                                         select a
              ).Distinct().ToListAsync();

            if (request.SupplierId == -1)
            {
                contract_lenses = await (from a in _db.Contract_Lens.Include(x => x.Lens)
                                         join c in _db.Stock on a.LensId equals c.LensId
                                         where a.ContractId == request.ContractId && c.WarehouseId == request.WarehouseId
                                         select a
              ).Distinct().ToListAsync();
            }

            return _mapper.Map<List<Contract_LensResponse>>(contract_lenses);
        }
        /// <summary>
        /// 合约窗体
        /// </summary>
        /// <returns></returns>
        public async Task<PageResponse<ContractResponse>> Query(PageRequest<ContractRequest> request)
        {
            var response = new PageResponse<ContractResponse>();
            var query = Where(request);
            var list = await query.Paging(request.PageIndex, request.PageSize).ToListAsync();
            response.TotalCount = await query.CountAsync();
            response.PageIndex = request.PageIndex;
            response.PageSize = request.PageSize;
            response.List = _mapper.Map<List<ContractResponse>>(list);
            return response;
        }
        /// <summary>
        /// 获取id的合约详情
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<ContractResponse> Detail(long id)
        {
            var model = await _db.Contract
                .Include(x => x.Contract_Customers).ThenInclude(x => x.Customer)
                .Include(x => x.Contract_Lenses).ThenInclude(x => x.Lens)
                .Include(x => x.Contract_Lens_SalesProcessConstraints).ThenInclude(x => x.Lens).FindByIdAsync(id);
            var response = _mapper.Map<ContractResponse>(model);
            return response;
        }
        /// <summary>
        /// 合约保存
        /// </summary>
        /// <param name="request"></param>
        /// <param name="isCheck"></param>
        /// <returns></returns>
        /// <exception cref="ApiException"></exception>
        public async Task Save(ContractSaveRequest request, bool isCheck = false)
        {
            if (request.CustomerIds.Count <= 0)
                throw new ApiException("客户信息不能为空!");
            if (request.Contract_Lenses.Count <= 0)
                throw new ApiException("镜片价格信息不能为空!");

            if (_db.Contract.Any(x => x.Name.ToLower() == request.Name && x.Id != request.Id))
                throw new ApiException("合约名称已存在!");
            Contract? model = _mapper.Map<Contract>(request);
            if (request.Id != null)
            {
                model = await _db.Contract.Include(x => x.Contract_Customers).Include(x => x.Contract_Lenses).Include(x => x.Contract_Lens_SalesProcessConstraints).FindByIdAsync(request.Id.Value);
                if (model == null)
                    throw new ApiException("合约不存在!");
                model.Name = request.Name;
                model.Type = request.Type;
                model.Money = request.Money;
                model.PrepaidMoney = request.PrepaidMoney;
                model.Period = request.Period;
                model.BeginOn = request.BeginOn;
                model.EndOn = request.EndOn;
                model.Remark = request.Remark;
                //_db.RemoveRange(model.Contract_Customers);
                //_db.RemoveRange(model.Contract_Lenses);
                //_db.RemoveRange(model.Contract_Lens_SalesProcessConstraints);
            }
            if (request.CustomerIds.Count > 0)
            {
                List<Contract_Customer> contract_Customers = new();
                foreach (var customerId in request.CustomerIds)
                {
                    Contract_Customer contract_Customer = new()
                    {
                        CustomerId = customerId
                    };
                    contract_Customers.Add(contract_Customer);
                }
                model.Contract_Customers = contract_Customers;
            }
            if (request.Contract_Lenses.Count > 0)
            {
                var list = new List<Contract_Lens>();
                foreach (var item in request.Contract_Lenses)
                {
                    var lens = await _db.Lens.Where(x => x.SalesLensCode == item.LensCode).FirstOrDefaultAsync() ?? throw new ApiException($"镜种{item.LensCode}不存在!");
                    var contractLens = _mapper.Map<Contract_Lens>(item);
                    contractLens.LensId = lens.Id;
                    list.Add(contractLens);
                }
                model.Contract_Lenses = list.Distinct().ToList();
            }
            if (request.Contract_Lens_SalesProcessConstraints != null && request.Contract_Lens_SalesProcessConstraints.Count > 0)
            {
                var list = new List<Contract_Lens_SalesProcessConstraint>();
                foreach (var item in request.Contract_Lens_SalesProcessConstraints)
                {
                    var lens = await _db.Lens.Where(x => x.SalesLensCode == item.LensCode).FirstOrDefaultAsync() ?? throw new ApiException($"镜种{item.LensCode}不存在!");
                    var contract_Lens_SalesProcessConstraint = _mapper.Map<Contract_Lens_SalesProcessConstraint>(item);
                    contract_Lens_SalesProcessConstraint.LensId = lens.Id;
                    list.Add(contract_Lens_SalesProcessConstraint);
                }
                model.Contract_Lens_SalesProcessConstraints = list.Distinct().ToList();
            }
            if (request.Id == null)
            {
                string number = await _serialNumberSvc.GetSerialNumber(SerialNumberTypeEnum.Contract);
                model.Number = number;
                model.Status = ContractStatusEnum.Pending.ToString();
                await _db.AddAsync(model);
            }
            if (isCheck)
                Check(model);
            await _db.SaveChangesAsync();
        }
        /// <summary>
        /// 合约审核
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task Check(long[] ids)
        {
            if (ids.Length <= 0)
                throw new ApiException("id不能为空!");

            var list = await _db.Contract.Include(x => x.Contract_Customers).Include(x => x.Contract_Lenses).Include(x => x.Contract_Lens_SalesProcessConstraints).Where(x => ids.Contains(x.Id)).ToListAsync();
            foreach (var model in list)
            {
                if (model.Contract_Customers.Count <= 0)
                    throw new ApiException($"合约{model.Number}没有客户信息!");
                if (model.Contract_Lenses.Count <= 0)
                    throw new ApiException($"合约{model.Number}没有镜片价格信息!");
                //if (model.Contract_Lens_SalesProcessConstraints.Count <= 0)
                //    throw new ApiException($"合约{l.Number}没有工序价格信息!");

                if (model.Status != ContractStatusEnum.Pending.ToString())
                    throw new ApiException($"合约{model.Number}不能审核!");

                Check(model);
            }
            await _db.SaveChangesAsync();
        }
        /// <summary>
        /// 合约弃审
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task UnCheck(long[] ids)
        {
            if (ids.Length <= 0)
                throw new ApiException("id不能为空!");

            var list = await _db.Contract.Where(x => ids.Contains(x.Id)).ToListAsync();
            foreach (var l in list)
            {
                if (l.Status != ContractStatusEnum.Checked.ToString())
                    throw new ApiException($"合约{l.Number}不能弃审!");

                l.Status = ContractStatusEnum.Pending.ToString();
                l.CheckedBy = null;
                l.CheckedByName = null;
                l.CheckedOn = null;
            }
            await _db.SaveChangesAsync();
        }
        /// <summary>
        /// 合约取消
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task Cancel(long[] ids)
        {
            if (ids == null)
                throw new ApiException("id不能为空!");

            var list = await _db.Contract.Where(x => ids.Contains(x.Id)).ToListAsync();
            foreach (var l in list)
            {
                if (l.Status == ContractStatusEnum.Canceled.ToString())
                    throw new ApiException($"合约{l.Number}不能取消!");

                l.Status = ContractStatusEnum.Canceled.ToString();
                //l.CheckedBy = null;
                //l.CheckedByName = null;
                //l.CheckedOn = null;
            }
            await _db.SaveChangesAsync();
        }

        /// <summary>
        /// 获取合约列表
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<List<ContractResponse>> GetContracts(PageRequest<ContractRequest> request)
        {
            var list = await Where(request).ToListAsync();
            return _mapper.Map<List<ContractResponse>>(list);
        }

        private IQueryable<Contract> Where(PageRequest<ContractRequest> request)
        {
            IQueryable<Contract> query = _db.Contract;
            if (!request.Query.Number.IsNullOrWhiteSpace())
            {
                query = query.Where(x => x.Number.Contains(request.Query.Number!));
            }
            if (!request.Query.Name.IsNullOrWhiteSpace())
            {
                query = query.Where(x => x.Name.Contains(request.Query.Name!));
            }
            if (!request.Query.CreatedByName.IsNullOrWhiteSpace())
            {
                query = query.Where(x => x.CreatedByName.Contains(request.Query.CreatedByName!));
            }
            if (request.Query.CreatedOnBegin != null)
            {
                query = query.Where(x => x.CreatedOn >= request.Query.CreatedOnBegin);
            }
            if (request.Query.CreatedOnEnd != null)
            {
                query = query.Where(x => x.CreatedOn <= request.Query.CreatedOnEnd.Value.ToEnd());
            }
            if (!request.Query.Type.IsNullOrWhiteSpace())
            {
                query = query.Where(x => x.Type == request.Query.Type);
            }
            if (!request.Query.Status.IsNullOrWhiteSpace())
            {
                query = query.Where(x => x.Status == request.Query.Status);
            }
            if (request.Query.Status == ContractStatusEnum.Checked.ToString())
            {
                query = query.OrderByDescending(x => x.CheckedOn);
            }
            else
            {
                query = query.OrderByDescending(x => x.CreatedOn);
            }
            return query;
        }
        private void Check(Contract model)
        {
            model.Status = ContractStatusEnum.Checked.ToString();
            model.CheckedBy = _currentUser.Id;
            model.CheckedByName = _currentUser.Name;
            model.CheckedOn = DateTime.Now;
        }
    }
}
